package flexconsole.model {
	import flexconsole.AppFacade;
	
	import flexunit.framework.Assert;
	
	import mx.collections.ListCollectionView;
	import mx.collections.XMLListCollection;
	import mx.events.CollectionEvent;
	import mx.logging.ILogger;
	import mx.logging.Log;
	import mx.utils.ObjectUtil;
	
	import org.puremvc.as3.patterns.proxy.Proxy;
	
	/**
	 * Concrete implementation of <code>ICategoryProxy</code>.
	 *
	 * @author ivanchoo
	 *
	 */
	public class CategoryProxy extends Proxy implements ICategoryProxy {
		
		static private const QNAME:String = "categories";
		
		static private var logger:ILogger = Log.getLogger("flexconsole.model.CategoryProxy");
		
		private var _source:XML;
		
		private var _collection:ListCollectionView;
		
		public function CategoryProxy(proxyName:String = null, source:XML = null) {
			super(proxyName);
			_source = source;
		}
		
		public function get source():XML {
			if (_source == null) {
				_source = new XML("<" + QNAME + " />");
			}
			return _source;
		}
		
		public function set source(xml:XML):void {
			_source = xml;
			
			if (_collection) {
				(_collection as XMLListCollection).source = source.children();
				(_collection as XMLListCollection).refresh();
			}
			sendNotification(AppFacade.DATA_CHANGE, null, getProxyName());
		}
		
		public function get collection():ListCollectionView {
			if (_collection == null) {
				_collection = new XMLListCollection(source.children());
				_collection.addEventListener(CollectionEvent.COLLECTION_CHANGE, onCollectionChange);
			}
			return _collection;
		}
		
		public function getName(xml:XML):String {
			Assert.assertNotNull(xml);
			return xml.hasOwnProperty("@uid") ? xml.@uid : null;
		}
		
		
		public function isSelected(xml:XML):Boolean {
			Assert.assertNotNull(xml);
			return xml.hasOwnProperty("@selected") ? xml.@selected == "true" : false;
		}
		
		public function isOpen(xml:XML):Boolean {
			Assert.assertNotNull(xml);
			return xml.hasOwnProperty("@open") ? xml.@open == "true" : false;
		}
		
		public function select(xml:XML, bool:Boolean):void {
			Assert.assertNotNull(xml);
			
			if (isSelected(xml) == bool) {
				return;
			}
			
			xml.@selected = bool ? "true" : "false";
			
			var children:XMLList = xml.children();
			var i:int = children.length();
			
			while (i--) {
				select(children[i], bool);
			}
			collection.itemUpdated(xml, "@selected", bool, !bool);
		}
		
		public function open(xml:XML, bool:Boolean):void {
			Assert.assertNotNull(xml);
			
			if (isOpen(xml) == bool) {
				return;
			}
			xml.@open = bool ? "true" : "false";
			collection.itemUpdated(xml, "@open", bool, !bool);
		}
		
		public function find(name:String):XML {
			Assert.assertNotNull(name);
			
			var xlist:XMLList = source.descendants("*").(@uid == name);
			return xlist && xlist.length() ? xlist[0] as XML : null;
		}
		
		public function add(name:String):XML {
			Assert.assertNotNull(name);
			
			var parts:Array = name.split(".");
			var part:String;
			var node:XML = source;
			var children:XMLList;
			var child:XML;
			var newNode:XML;
			var uid:String = "";
			var i:int;
			
			for each (part in parts) {
				uid += part;
				children = node.child(part);
				
				//  Find the child
				if (children.length()) {
					//  Found, we decend into it
					node = children[0];
				} else {
					//  not found, we iterate and find the correct position
					children = node.children();
					i = 0;
					
					for each (child in children) {
						if (ObjectUtil.compare(child.localName().toString(), part) == 1) {
							break;
						}
						i++;
						child = null;
					}
					newNode = new XML("<" + part + " />");
					newNode.@uid = uid;
					select(newNode, node == source ? true : isSelected(node));
					open(newNode, node == source ? true : isOpen(node));
					
					if (child) {
						node.insertChildBefore(child, newNode);
					} else if (node == source) {
						collection.addItemAt(newNode, i);
					} else {
						node.appendChild(newNode);
					}
					node = newNode;
					collection.itemUpdated(node);
				}
				uid += ".";
			}
			return node;
		}
		
		public function remove(xml:XML):void {
			Assert.assertNotNull(xml);
			
			if (xml == source) {
				return;
			}
			var name:String = getName(xml);
			
			if (!name || !find(name)) {
				return;
			}
			var parts:Array = name.split(".");
			var lastPart:String = parts.length ? parts.pop() as String : null;
			
			if (!lastPart) {
				return;
			}
			var parentXML:XML = xml.parent() as XML;
			
			if (!parentXML) {
				return;
			}
			delete parentXML.child(lastPart)[0];
		}
		
		public function clear():void {
			collection.removeAll();
		}
		
		protected function onCollectionChange(event:CollectionEvent):void {
			sendNotification(AppFacade.DATA_CHANGE, event.items, getProxyName());
		}
	
	
	
	}
}

